/**
 * 自定义钩子用于管理浏览器存储
 * 它允许您在React组件中订阅和读取存储的变化
 *
 * @param key 存储的键名
 * @param defaultValue 如果指定的键在存储中不存在时的默认值
 * @returns 返回一个包含当前存储值和更新存储值函数的数组
 */
export const useStorage = (key: string, defaultValue: unknown) => {
  /**
   * 订阅存储变化的函数
   * 当存储变化时，它会触发回调函数
   *
   * @param callback 当存储变化时调用的回调函数
   * @returns 返回一个用于取消订阅的函数
   */
  const subscribe = (callback: () => void) => {
    // 监听存储事件并调用回调函数
    window.addEventListener('storage', (e) => {
      console.log('触发了', e);
      callback();
    });
    // 返回一个用于取消事件监听的函数
    return () => {
      window.removeEventListener('storage', callback);
    };
  };

  /**
   * 获取当前存储快照的函数
   * 它从本地存储中读取值并解析为JavaScript对象
   * 如果指定的键不存在，则返回默认值
   *
   * @returns 返回当前存储的值或默认值
   */
  const getSnapshot = () => {
    return (
      (localStorage.getItem(key)
        ? JSON.parse(localStorage.getItem(key)!)
        : null) || defaultValue
    );
  };

  /**
   * 更新存储值的函数
   * 它将值序列化为JSON字符串并存储到本地存储中
   * 存储更新后，它还会触发一个存储事件
   *
   * @param value 要存储的值
   */
  const setStorage = (value: unknown) => {
    localStorage.setItem(key, JSON.stringify(value));
    window.dispatchEvent(new Event('storage'));
  };

  // 使用useSyncExternalStore同步外部存储和React组件状态
  // 这个钩子允许React组件订阅外部数据源的变化
  const res = useSyncExternalStore(subscribe, getSnapshot);

  // 返回当前存储值和更新存储值的函数
  return [res, setStorage];
};
